﻿#region Using Directives

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Kongo.Properties;

#endregion Using Directives


namespace Kongo
{
    partial class Variable
    {
        // Helper class that parses the variable
        private class Parser
        {
            #region Fields

            private Variable variable;
            private string expression;

            #endregion Fields


            #region Methods

            public void PunchItChewy()
            {
                int endIndex = 0;
                List<string> members = new List<string>();
                List<FilterInfo> filters = new List<FilterInfo>();

                // The first match must be the variable
                Match m = regex.Match(expression);
                if (!m.Success || m.Index != endIndex || m.Groups[SEPARATOR].Value.Length != 0)
                    throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "variable name"));

                // Got the variable
                variable.key = m.Groups[ELEMENT].Value;
                if (variable.key.StartsWith("\""))
                {
                    // This is a constant string and needs to be un-escaped
                    variable.isConstant = true;
                    variable.key = Helpers.UnescapeStringConstant(variable.key);
                }

                // Get any optional members
                endIndex = m.Index + m.Length;
                m = m.NextMatch();
                while (m.Success && m.Groups[SEPARATOR].Value == ".")
                {
                    // There can be no space between matches
                    if (m.Index != endIndex)
                        throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "member"));

                    members.Add(m.Groups[ELEMENT].Value);
                    endIndex = m.Index + m.Length;
                    m = m.NextMatch();
                }

                // Get any optional filters
                while (m.Success && m.Groups[SEPARATOR].Value == "|")
                {
                    if (m.Index != endIndex)
                        throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "filter"));

                    FilterInfo fi = new FilterInfo();
                    fi.Key = m.Groups[ELEMENT].Value;
                    
                    endIndex = m.Index + m.Length;
                    m = m.NextMatch();

                    // Look for an optional argument
                    if (m.Success && m.Groups[SEPARATOR].Value == ":")
                    {
                        if (m.Index != endIndex)
                            throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "filter argument"));

                        string arg = m.Groups[ELEMENT].Value;
                        if (!arg.StartsWith("\""))
                            throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "filter argument"));

                        fi.Arg = Helpers.UnescapeStringConstant(arg);
                        endIndex = m.Index + m.Length;
                        m = m.NextMatch();
                    }

                    filters.Add(fi);
                }

                // There should be no remaining text
                if (endIndex != expression.Length)
                    throw new ArgumentException(Helpers.Format(Resource.Argument_InvalidExpression, "character or sequence"));

                variable.members = members.ToArray();
                variable.filters = filters.ToArray();
            }

            #endregion Methods


            #region Constructors

            public Parser(Variable variable, string expression)
            {
                Debug.Assert(variable != null, "The 'variable' argument was null.");
                Debug.Assert(expression != null, "The 'expression' argument was null.");

                this.variable = variable;
                this.expression = expression;
            }

            #endregion Constructors
        }
    }
}
